---@class Battle.SkillReleaseEmitter:Battle.SkillComponent
local SkillReleaseEmitter = Battle.CreateClass("SkillReleaseEmitter",Battle.SkillComponent)
Battle.SkillReleaseEmitter = SkillReleaseEmitter


function SkillReleaseEmitter:OnCreate()
    self.pos = Vector3.New()

    self.isActive = true
    self.resName = nil
    self.isRect = false
    ---@type Battle.IRangeSelector
    self.rangeSelector = nil
    ---@type Battle.Entity[]
    self.targetList = {}
    ---@type Battle.Entity
    self.releaseTarget = nil
    self:Register()
end
function SkillReleaseEmitter:OnDestroy()
    self:UnRegister()
    self:EndPos()
end
function SkillReleaseEmitter:OnInitialized()
    self:InitRange()
end
function SkillReleaseEmitter:Register()
    if self.skill:IsNeedHand() then
        local eventSystem = self.skill.actor.eventSystem
        eventSystem:Register(Battle.Event.SkillReleaseUpdatePos,self.Event_ReleaseUpdatePos,self)
        eventSystem:Register(Battle.Event.SkillEmit,self.Event_SkillEmit,self)
    end
end
function SkillReleaseEmitter:UnRegister()
    local eventSystem = self.skill.actor.eventSystem
    eventSystem:UnRegister(Battle.Event.SkillReleaseUpdatePos,self.Event_ReleaseUpdatePos,self)
    eventSystem:UnRegister(Battle.Event.SkillEmit,self.Event_SkillEmit,self)
end
function SkillReleaseEmitter:InitRange()
    local param  = self.skill.skillData.rangeScopeParam
    self.isRect = false
    if param.type == Battle.SkillScopeType.Self_Rect then
        self.isRect = true
    end
    if param.type == Battle.SkillScopeType.HandCircle and param.height ~= nil then
        self.isRect = true
    end
    if param.type == Battle.SkillScopeType.HandLine then
        self.isRect = true
    end
    if self.isRect then
        self.rangeSelector = Battle.RectangleSelector.New()
    else
        self.rangeSelector = Battle.SectorSelector.New()
    end
end
---@return Battle.Entity[]
function SkillReleaseEmitter:CalcDamageTargetList()
    table.clear(self.targetList)
    if self.skill.skillData.f_Company == 2 then --群体
        local param  = self.skill.skillData.rangeScopeParam
        self.rangeSelector:Init(self:GetReleasePos(),self:GetReleaseForward(),param.width,param.height,360)
        local list = {}
        self.rangeSelector:CalculateTargets(list)
        for k,v in pairs(list) do
            if(self:CheckCampParam(v)) then
                local count = self.skill.skillData.f_Quantity
                if count > 0 and #self.targetList >= count then
                    break
                end
                table.insert(self.targetList,v)
            end
        end
    else
        local target = self:CalcReleaseTarget()
        if target then
            table.insert(self.targetList,target)
        end
    end
    return self.targetList
end
function SkillReleaseEmitter:GetDamageTargetList()
    return self.targetList
end
function SkillReleaseEmitter:CalcReleaseTarget()
    self.releaseTarget = self:DoCalcTarget(self.skill.releaseRadius)
    return self.releaseTarget
end
function SkillReleaseEmitter:GetSearchTarget(searchRadius)
    return self:DoCalcTarget(searchRadius)
end
---@private
function SkillReleaseEmitter:DoCalcTarget(radius)
    local targetRule = self.skill.skillData.f_TargetRule
    local target
    if targetRule == 2 then -- 绝对生命值最低
        target = self:GetLowAbsoluteHPActor(radius)
    elseif targetRule == 3 then --攻击最高
        target = self:GetHighAtkActor(radius)
    elseif targetRule == 4 then --手动选择
        return nil
    elseif targetRule == 5 then
        target = self:GetRandomActor(radius)
    else--距离最近
        target = self:GetNearestActor(radius)
    end
    return target
end
---@private
function SkillReleaseEmitter:GetLowAbsoluteHPActor(skillRadius)
    local target
    local list = Battle.ActorManager.GetActorList()
    for k,v in pairs(list) do
        local flag = self:CheckCampParam(v)
        if flag and self:InRange(skillRadius,v) then
            if target == nil then
                target = v
            elseif v:GetHp() < target:GetHp() then
                target = v
            end
        end
    end
    return target
end
---@private
function SkillReleaseEmitter:GetNearestActor(skillRadius)
    local actor = self.skill.actor
    local point = actor.pos
    local list = Battle.ActorManager.GetActorList()
    local minDis = 10000000000
    local target
    for k,v in pairs(list) do
        local flag = self:CheckCampParam(v)
        if flag then
            local r = skillRadius + v.radius
            local dis = Battle.BattleUtil.DistanceSqr(point,v.pos)
            if dis < r * r and dis < minDis then
                minDis = dis
                target = v
            end
        end
    end
    return target
end

---@private
function SkillReleaseEmitter:GetHighAtkActor(skillRadius)
    local target
    local list = Battle.ActorManager.GetActorList()
    for k,v in pairs(list) do
        local flag = self:CheckCampParam(v)
        if flag and self:InRange(skillRadius,v) then
            if target == nil then
                target = v
            elseif v.attrSystem:GetAtk() > target.attrSystem:GetAtk() then
                target = v
            end
        end
    end
    return target
end
---@param entity Battle.Entity
function SkillReleaseEmitter:InRange(radius, entity)
    if radius == 0 then return true end
    return Battle.BattleUtil.IsCircleIntersection(self.skill.actor.pos,radius,entity.pos,entity.radius)
end
---@private
function SkillReleaseEmitter:GetRandomActor(skillRadius)
    local tempList = {}
    local canRepeat = self.skill.skillData.f_RepeatChoice
    local list = Battle.ActorManager.GetActorList()
    for k,v in pairs(list) do
        local flag = self:CheckCampParam(v)
        if flag and self:InRange(skillRadius,v) then
            table.insert(tempList,v)
        end
    end
    if #tempList == 0 then return nil end
    local index = math.random(1,#tempList)
    return tempList[index]
end

---@return Battle.Entity
function SkillReleaseEmitter:GetReleaseTarget()
   return self.releaseTarget
end
---@param entity Battle.Entity
function SkillReleaseEmitter:CheckCampParam(entity)
    local skillData = self.skill.skillData
    local curCamp = self.skill.actor.camp
    local campParam = skillData.f_Camp
    local enemyCamp = Battle.BattleUtil.GetEnemyCamp(curCamp)
    local flag = false
    --阵营
    if (campParam.type == 1 and entity.camp == curCamp) or (campParam.type == 2 and entity.camp == enemyCamp) or campParam.type == 3 then
        flag = true
    end
    if not flag then return false end
    if campParam.summon == 1 and entity.isSummon then--不包含召唤物
        return false
    end
    if campParam.summon == 2 and not entity.isSummon then--只包含召唤物
        return false
    end
    if campParam.summon == 3 and entity.actorType ~= Battle.ActorType.Lord then--主角
        return false
    end
    --单位类型
    local unitType = skillData.f_UnitType
    local unitFlag = unitType == 1 or (unitType == 2 and entity:IsUnitFly()) or (unitType == 3 and entity:IsUnitGround())
    flag = flag and unitFlag
    flag = flag and self.skill.actor:CanTarget(entity)
    return flag
end

function SkillReleaseEmitter:GetReleasePos()
    if self.skill.skillData.f_Company == 1 then --单体还是群体
        local target = self.skill.actor
        if self.skill.skillData.releaseType == Battle.ReleaseType.RemoteImmediate then
            local t = self:CalcReleaseTarget()
            if t ~= nil then
                target = t
            end
        end
        return target:GetPos()
    end
    local scope = self.skill.skillData.rangeScopeParam.type
    if scope == Battle.SkillScopeType.HandCircle then
        return self.pos
    elseif scope == Battle.SkillScopeType.Self_Rect or scope == Battle.SkillScopeType.Self_Circle then
        return self.skill.actor:GetPos()
    else
        local target = self:CalcReleaseTarget()
        if target == nil then
            target = self.skill.actor
        end
        return target:GetPos()
    end
end
function SkillReleaseEmitter:GetReleaseForward()
    if self.skill.skillData.rangeScopeParam.type == Battle.SkillScopeType.HandLine then
        local p = self.pos - self.skill.actor:GetPos()
        p.y = 0
        p:SetNormalize()
        return p
    end
    return self.skill.actor:GetForward()
end
function SkillReleaseEmitter:SetHandPos(pos)
    self.pos:SetV(pos)
end
function SkillReleaseEmitter:UpdateMovePos()

    local flag,wx,wy,wz = Battle.SceneMgr.GetRaycastScenePos()
    if flag then
        self.pos:Set(wx,wy,wz)
        ---@type Battle.SkillRangeTipComponent
        local tip = self.skill:GetComponent(Battle.SkillRangeTipComponent:GetType())
        tip:Show(wx,wy,wz)
    end
end

function SkillReleaseEmitter:EndPos()
    ---@type Battle.SkillRangeTipComponent
    local tip = self.skill:GetComponent(Battle.SkillRangeTipComponent:GetType())
    tip:Hide()
end

---@param args SkillArgs
function SkillReleaseEmitter:Event_ReleaseUpdatePos(args)
    local skill = args.skill
    if skill ~= self.skill then return end
    if self.skill.actor:IsDead() then return end
    self:UpdateMovePos()
end
---@param args SkillArgs
function SkillReleaseEmitter:Event_SkillEmit(args)
    local skill = args.skill
    if skill ~= self.skill then return end
    self:EndPos()
    if skill.actor:IsDead() then
        return
    end
    self.skill.actor.aiSystem:SetBlackboardValue("hand_skill",true)

end
